#include<stdio.h>
#include<stdlib.h>
#include<strings.h>
#include<signal.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#define ARG argv[i]
#define BUF_SIZE 1024

typedef int fd_t;

void errorHandle(int sig,char * argv[]);
void sendfile(int socket);
void sigHandle(int sig);

fd_t server_fd,client_fd;

const char header[] = {
			"HTTP/1.1 200 OK\r\n"
			"Server: Goll's tiny web server\r\n"
			"Connection: close\r\n"
			"Content-Type: text/plain\r\n"
			"\r\n"
};
int H_len = sizeof(header) - 1;

const char bad_request[] = {
			"HTTP/1.0 400 BAD REQUEST\r\n"
};
int BR_len = sizeof(bad_request) - 1;

const char method_not_supported[] = {
			"HTTP/1.1 501 Method Not Implemented\r\n"
			"Content-Type: text/html\r\n"
			"\r\n"
			"<HTML><HEAD><TITLE>Method Not Implemented\r\n"
			"</TITLE></HEAD>\r\n"
			"<BODY><P>HTTP request method not supported.\r\n"
			"</BODY></HTML>\r\n"};
int MNS_len = sizeof(method_not_supported) - 1;

const char not_found[] = {
			"HTTP/1.1 404 NOT FOUND\r\n"
			"Content-Type: text/html\r\n"
			"\r\n"
			"<HTML><TITLE>Not Found</TITLE>\r\n"
			"<BODY><P>The server could not fulfill\r\n"
			"your request because the resource specified\r\n"
			"is unavailable or nonexistent.\r\n"
			"</BODY></HTML>\r\n"};
int NF_len = sizeof(not_found) - 1;

int main(int argc,char * argv[])
{
	struct sockaddr_in server_addr,client_addr;
	int port = 0;
	int dir_arg = 0;
	if(argc == 1)
		errorHandle(-1,argv);

	//处理参数
	for(int i = 1;i < argc;i++)
	{
		if(strcmp("-port",ARG) == 0)
		{
			i++;
			if(i < argc)
				port = atoi(ARG);
			else
				errorHandle(0,argv);
			continue;
		} else if(strcmp("-dir",ARG) == 0)
		{
			i++;
			if(i < argc)
				dir_arg = i;
			else
				errorHandle(0,argv);
			continue;
		}
		errorHandle(i,argv);
	}

	//检查端口是否不为零
	if(!port)
	{
		printf("You don't set port\n");
		printf("Determine port as 8080\n");
		port = 8080;
	}

	if(!dir_arg)
	{
		printf("You don't set the dir store the file to send\n");
		errorHandle(0,argv);
	}
	if((server_fd = socket(AF_INET,SOCK_STREAM,0)) == 0)
		errorHandle(-2,NULL);
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(port);
	if(bind(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0)
		errorHandle(-2,NULL);
	printf("Bind completed.\n");
	if(listen(server_fd,20) < 0)
		errorHandle(-2,NULL);
	unsigned int addr_sz = sizeof(client_addr);
	signal(SIGINT,sigHandle);
	while(1)
	{
		printf("Waiting for connection...\n");
		//如果接受客户端失败
		//则关闭客户端套接字
		if((client_fd = accept(server_fd,(struct sockaddr *)&client_addr,&addr_sz)) < 0)
		{
			printf("Failed when accept.\n");
			printf("Close the connection.\n");
			close(client_fd);
			continue;
		}
		printf("Connected.\n");
		//现在还只支持单线程
		//多线程等放假了再说吧
		sendfile(client_fd);
	}
	return 0;
}

void errorHandle(int sig,char * argv[])
{
	switch(sig) {
		case -2:
			perror("Error");
			exit(-1);
		case -1:
			break;
		case 0:
			printf("Not enough argument\n");
			break;
		default:
			printf("Unkonwn command:\'%s\'\n",argv[sig]);
			break;
	}
	printf("Usage : %s -port <port> -file <file_path>\n",argv[0]);
	exit(-1);
}

void sigHandle(int sig)
{
	printf("Exit\n");
	close(client_fd);
	close(server_fd);
	exit(0);
}

void sendfile(int sock)
{
	FILE * fp;
	int i,j = 0;
	char buf[BUF_SIZE] = {0};
	char * pBuf = &buf[0];
	//rewind(fp);
	while((i = recv(sock,pBuf,BUF_SIZE,0)) > 0)
	{
		//获取第一行的长度
		while(buf[j] != '\n' && j < BUF_SIZE)
			j++;
		//避免buf中的信息被接收的信息覆盖
		pBuf = (char *)NULL;
		if(j > 13)
		{
			buf[j] = 0;
			break;
		}
		else
		{
			j = -1;
			break;
		}
	}

	if(j < 0)
	{
error_msg:
		printf("Something wrong happeneds\n");
		send(sock,bad_request,BR_len,0);
		close(sock);
		return;
	}

	printf("Header:%s\n",buf);

	int k = 1;
	char * request[3];
	request[0] = &buf[0];

	for(int r = 0;k < 3;k++)
	{
loop:
		if(j > r)
		{
			if(buf[r] != ' ')
			{
				r++;
				goto loop;
			} else {
				buf[r] = 0;
				r++;
				request[k] = &buf[r];
			}
		} else
			break;
	}

	if(k < 2)
		goto error_msg;
	printf("Method:%s\nURL:%s\nVer:%s\n",request[0],request[1],request[2]);
	request[1]++;
	if(strcmp("GET",request[0]) == 0)
	{
		printf("Succeed\n");
		if(strcmp("HTTP/1.1\r",request[2]) != 0)
			goto error_msg;
		fp = fopen(request[1],"rb");
		if(fp == NULL)
		{
			send(sock,not_found,NF_len,0);
			close(sock);
			return;
		}
		printf("Send header\n");
		send(sock,header,H_len,0);
		rewind(fp);
		printf("Send file \'%s\'\n",request[1]);
		for(int flen;(flen = fread(buf,1,BUF_SIZE,fp)) > 0;)
			send(sock,buf,flen,0);
		fclose(fp);
		close(sock);
		return;
	}
	printf("Method not supported\n");
	send(sock,method_not_supported,MNS_len,0);
	close(sock);
	return;
}
